﻿#include "AudioDevices.h"

#define sizeof_array(a) (sizeof(a) / sizeof(a[0]))

const int sample_rate_table[]={
  192000,96000,48000,44100,32000,16000,11025,8000
};

const int audio_device_channels[]={
  2,1
};

static QString toString(QAudioFormat::SampleFormat sampleFormat)
{
    switch (sampleFormat) {
    case QAudioFormat::UInt8:
        return "Unsigned 8 bit";
    case QAudioFormat::Int16:
        return "Signed 16 bit";
    case QAudioFormat::Int32:
        return "Signed 32 bit";
    case QAudioFormat::Float:
        return "Float";
    default:
        return "Unknown";
    }
}

AudioDevice::AudioDevice(QWidget *parent)
{
    m_devices = new QMediaDevices(parent);

    cmbInputDevice = new QComboBox();
    cmbInputDeviceChannel = new QComboBox();
    cmbInputDeviceSampleRate = new QComboBox();
    cmbInputDeviceFormat = new QComboBox();
//    labInputDevice = new QLabel();
//    labInputDeviceSampleRate = new QLabel();
//    labInputDeviceChannel = new QLabel();
//    labInputDeviceFormat = new QLabel();

    cmbOutputDeviceSampleRate = new QComboBox();
    cmbOutputDevice = new QComboBox();
    cmbOutputDeviceChannel = new QComboBox();
    cmbOutputDeviceFormat = new QComboBox();
//    labOutputDevice = new QLabel();
//    labOutputDeviceSampleRate = new QLabel();
//    labOutputDeviceChannel = new QLabel();
//    labOutputDeviceFormat = new QLabel();

    vLayout = new QVBoxLayout();
//    gridLayoutInput = new QGridLayout();
//    gridLayoutOutput = new QGridLayout();
    formLayoutInput = new QFormLayout();
    formLayoutOutput = new QFormLayout();
    boxInput = new QGroupBox(tr("Input"));
    boxOutput = new QGroupBox(tr("Output"));

    connect(cmbInputDevice, &QComboBox::currentIndexChanged, this, &AudioDevice::input_device_select_changed);
    connect(cmbOutputDevice,&QComboBox::currentIndexChanged, this, &AudioDevice::output_device_select_changed);
    update_input_audio_device();
    update_output_audio_device();
//    labInputDevice->setText(tr("input:"));
//    labInputDeviceSampleRate->setText(tr("sample rate:"));
//    labInputDeviceChannel->setText(tr("channel:"));
//    labInputDeviceFormat->setText(tr("format:"));
//    labOutputDevice->setText(tr("output:"));
//    labOutputDeviceSampleRate->setText(tr("sample rate:"));
//    labOutputDeviceChannel->setText(tr("channel:"));
//    labOutputDeviceFormat->setText(tr("format:"));

//    gridLayoutInput->addWidget(labInputDevice,0,0,1,1);
//    gridLayoutInput->addWidget(cmbInputDevice,0,1,1,1);
//    gridLayoutInput->addWidget(labInputDeviceSampleRate,1,0,1,1);
//    gridLayoutInput->addWidget(cmbInputDeviceSampleRate,1,1,1,1);
//    gridLayoutInput->addWidget(labInputDeviceChannel,2,0,1,1);
//    gridLayoutInput->addWidget(cmbInputDeviceChannel,2,1,1,1);
//    gridLayoutInput->addWidget(labInputDeviceFormat,3,0,1,1);
//    gridLayoutInput->addWidget(cmbInputDeviceFormat,3,1,1,1);

//    gridLayoutOutput->addWidget(labOutputDevice,0,0,1,1);
//    gridLayoutOutput->addWidget(cmbOutputDevice,0,1,1,1);
//    gridLayoutOutput->addWidget(labOutputDeviceSampleRate,1,0,1,1);
//    gridLayoutOutput->addWidget(cmbOutputDeviceSampleRate,1,1,1,1);
//    gridLayoutOutput->addWidget(labOutputDeviceChannel,2,0,1,1);
//    gridLayoutOutput->addWidget(cmbOutputDeviceChannel,2,1,1,1);
//    gridLayoutOutput->addWidget(labOutputDeviceFormat,3,0,1,1);
//    gridLayoutOutput->addWidget(cmbOutputDeviceFormat,3,1,1,1);
//    boxInput->setLayout(gridLayoutInput);
//    boxOutput->setLayout(gridLayoutOutput);

    formLayoutInput->addRow(tr("input:"),cmbInputDevice);
    formLayoutInput->addRow(tr("sample rate:"),cmbInputDeviceSampleRate);
    formLayoutInput->addRow(tr("format:"),cmbInputDeviceFormat);
    formLayoutInput->addRow(tr("channel:"),cmbInputDeviceChannel);

    formLayoutOutput->addRow(tr("input:"),cmbOutputDevice);
    formLayoutOutput->addRow(tr("sample rate:"),cmbOutputDeviceSampleRate);
    formLayoutOutput->addRow(tr("format:"),cmbOutputDeviceFormat);
    formLayoutOutput->addRow(tr("channel:"),cmbOutputDeviceChannel);

    boxInput->setLayout(formLayoutInput);
    boxOutput->setLayout(formLayoutOutput);

    vLayout->addWidget(boxInput);
    vLayout->addWidget(boxOutput);

    setLayout(vLayout);

    input_device_select_changed(0);
    output_device_select_changed(0);
}

AudioDevice::~AudioDevice()
{

}

QAudioDevice AudioDevice::get_input_device()
{
    return m_input_device_info;
}

QAudioDevice AudioDevice::get_output_device()
{
    return m_output_device_info;
}

void AudioDevice::update_input_audio_device()
{
    const auto devices = m_devices->audioInputs();
    cmbInputDevice->clear();
    for (auto &deviceInfo : devices)
        cmbInputDevice->addItem(deviceInfo.description(), QVariant::fromValue(deviceInfo));
    cmbInputDevice->setCurrentIndex(0);
}

void AudioDevice::update_output_audio_device()
{
    const auto devices = m_devices->audioOutputs();
    cmbOutputDevice->clear();
    for (auto &deviceInfo : devices)
        cmbOutputDevice->addItem(deviceInfo.description(), QVariant::fromValue(deviceInfo));
    cmbOutputDevice->setCurrentIndex(0);
}

void AudioDevice::input_device_select_changed(int idx)
{
    if(cmbInputDevice->count() == 0)
    {
        return ;
    }
    m_input_device_info = cmbInputDevice->itemData(idx).value<QAudioDevice>();
    cmbInputDeviceSampleRate->clear();
    for(int i=0; i<sizeof_array(sample_rate_table); i++)
    {
        if((sample_rate_table[i] <= m_input_device_info.maximumSampleRate()) && (sample_rate_table[i] >= m_input_device_info.minimumSampleRate()))
        {
            cmbInputDeviceSampleRate->addItem(QString("%1").arg(sample_rate_table[i]));
        }
    }
    cmbInputDeviceChannel->clear();
    for(int i=0; i<sizeof_array(audio_device_channels); i++)
    {
        if((audio_device_channels[i] <= m_input_device_info.maximumChannelCount()) && (audio_device_channels[i] >= m_input_device_info.minimumChannelCount()))
        {
            cmbInputDeviceChannel->addItem(QString("%1").arg(audio_device_channels[i]));
        }
    }
    cmbInputDeviceFormat->clear();
    const QList<QAudioFormat::SampleFormat> sampleFormats = m_input_device_info.supportedSampleFormats();
    for (auto sampleFormat : sampleFormats)
        cmbInputDeviceFormat->addItem(toString(sampleFormat));
    emit input_device_changed(m_input_device_info);
}

void AudioDevice::output_device_select_changed(int idx)
{
    if(cmbOutputDevice->count() == 0)
    {
        return ;
    }
    m_output_device_info = cmbOutputDevice->itemData(idx).value<QAudioDevice>();
    cmbOutputDeviceSampleRate->clear();
    for(int i=0; i<sizeof_array(sample_rate_table); i++)
    {
        if((sample_rate_table[i] <= m_output_device_info.maximumSampleRate()) && (sample_rate_table[i] >= m_output_device_info.minimumSampleRate()))
        {
            cmbOutputDeviceSampleRate->addItem(QString("%1").arg(sample_rate_table[i]));
        }
    }
    cmbOutputDeviceChannel->clear();
    for(int i=0; i<sizeof_array(audio_device_channels); i++)
    {
        if((audio_device_channels[i] <= m_output_device_info.maximumChannelCount()) && (audio_device_channels[i] >= m_output_device_info.minimumChannelCount()))
        {
            cmbOutputDeviceChannel->addItem(QString("%1").arg(audio_device_channels[i]));
        }
    }
    cmbOutputDeviceFormat->clear();
    const QList<QAudioFormat::SampleFormat> sampleFormats = m_output_device_info.supportedSampleFormats();
    for (auto sampleFormat : sampleFormats)
        cmbOutputDeviceFormat->addItem(toString(sampleFormat));
    emit output_device_changed(m_output_device_info);
}

